#!/usr/bin/env python3

#
# This script parses the opcode.swift file and then emits a program.proto file.
#

import re
import datetime

OPCODESSWIFT_FILE = "../FuzzIL/Opcodes.swift"

START = f"// Copyright {datetime.date.today().year} Google LLC"
START += """
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file is autogenerated. Please check the README.

syntax = "proto3";
package fuzzilli.protobuf;

import "operations.proto";

message Instruction {
    // The operation is either encoded as an index, referring to the nth operation
    // (so that shared operations are also only present once in the protobuf), or
    // as one of the many concrete Operation messages.
    repeated uint32 inouts = 1;
    oneof operation {
        uint32 opIdx = 2;
"""

END = """    }
}

message Program {
    bytes uuid = 1;
    repeated Instruction code = 2;
    map<sint32, string> comments = 3;
    Program parent = 4;
}
"""

def parse_opcodes():
    opcodes = []
    with open(OPCODESSWIFT_FILE, "r") as f:
        for line in f.readlines():
            obj = re.search("^\s*case `?(\w*)`?\(", line)
            if obj is not None:
                opcodes.append(obj.group(1))

    return opcodes


def main():
    opcodes = parse_opcodes()

    with open("program.proto", "w") as f:
        f.write(START)

        for i, opcode in enumerate(opcodes):
            upper_case = chr(ord(opcode[0]) - 0x20) + opcode[1:]
            spaces = "    "
            f.write(f"{spaces * 2}{upper_case} {opcode} = {i + 3};\n")

        f.write(END)

main()



